

local assert     = assert
local require    = require
local bit        = bit
local coroutine  = coroutine
local debug      = debug
local io         = io
local pairs      = pairs
local ipairs     = ipairs
local math       = math
local os         = os
local print      = print
local pcall      = pcall
local xpcall     = xpcall
local rawget     = rawget
local rawset     = rawset
local select     = select
local string     = string
local table      = table
local tonumber   = tonumber
local tostring	 = tostring
local error      = error
local type       = type
local unpack     = unpack
local setmetatable = setmetatable
local getmetatable = getmetatable
local math_random = math.random
local ngx = ngx


local table_concat = table.concat

local string_char  = string.char
local string_sub   = string.sub
local string_byte  = string.byte
local string_gsub  = string.gsub
local string_find  = string.find
local string_upper = string.upper

local math_fmod   = math.fmod
local math_floor  = math.floor
local math_pow    = math.pow


----数据变量----
local uu         = require("modules.commhm.utils");
local log        = require("modules.commhm.log");
local ns_time    = require("modules.commhm.time");
local ns_env     = require("modules.env.env");
local hmac 		 = require("modules.commhm.resty.hmac");
local ns_network = require('modules.commhm.network');

local Log = log.debug;


local FOO = {
	_VERSION = '0.12.1',

	auth_key = "c8c93222583741bd828579b3d3efd43b";

	s_act_private_key  = '28871f94adcd2e17a776bcd6bffd4002';	-- 服务器内部

	s_cmd_private_key  = '28871f94adcd2e17a776bcd6bffd4002';	-- 客户端请求

	s_cpid = 'ac5252e80ef7fe0a90e5c5ac7a9671d6';

	s_hmac_SHA256 = 'bc630af4e7cd657d6ec8588184486924';

	t_product_key = {
		[85] = 'c1bcddf532fdd806d4b2295b181e1f25'; -- 安卓
		[86] = '8733ee1263520df36e77637352200ef9'; -- IOS
	};

	login_SDK_server_url = {
		"https://loginsdk.mini1.cn/cp/token/",
	};
};

if  ns_env.debug == 1 or ns_env.debug == 11 then
	FOO.auth_key = "c8c93222583741bd828579b3d3efd43b_1";

	FOO.s_act_private_key  = '28871f94adcd2e17a776bcd6bffd4002';	-- 服务器内部

	FOO.s_cmd_private_key  = '28871f94adcd2e17a776bcd6bffd4002';	-- 客户端请求

	FOO.s_cpid  = '02411f31180988a05f3ea6b15b6fddfb';

	FOO.s_hmac_SHA256 = 'af70fa8ed37c22ccd0251c03068cf957';

	FOO.t_product_key = {
		[85] = '86707f14a26946af69ac98811740cfea'; -- 安卓
		[86] = '617a4c60b39d0be3c06a02b3f8889a7d'; -- IOS
	};

	FOO.login_SDK_server_url = {
		"https://test-loginsdk.mini1.cn/cp/token/",
	};
end

if  ns_env.debug == 2 then
	FOO.s_act_private_key  = '28871f94adcd2e17a776bcd6bffd4002';	-- 服务器内部

	FOO.s_cmd_private_key  = '28871f94adcd2e17a776bcd6bffd4002';	-- 客户端请求

	FOO.s_cpid  = '02411f31180988a05f3ea6b15b6fddfb';

	FOO.s_hmac_SHA256 = 'af70fa8ed37c22ccd0251c03068cf957';

	FOO.t_product_key = {
		[85] = '86707f14a26946af69ac98811740cfea'; -- 安卓
		[86] = '617a4c60b39d0be3c06a02b3f8889a7d'; -- IOS
	};

	FOO.login_SDK_server_url = {
		"https://releasetest.mini1.cn:13001/cp/token/",
	};
end
--------------------------------------
----检查一个过滤条件，跟客户端函数功能一样(多一个参数t_)
--- condition_configs 配置项目的值
--- t_ = { uin=123123, apiid="0.232.2" lang=1 }
--- 默认值， 默认为false
---
--- 例子：ns_auth_comm_checker.check_apiid_ver_conditions( ns_config.config_version.safety_funcheck.map_share )
---
FOO.check_apiid_ver_conditions = function ( condition_configs, t_, default_ )
	if  condition_configs then
		--超级白名单
		if  condition_configs.super_uin_list then
			local uin = t_.uin
			local pos_  = string.find( ',' .. condition_configs.super_uin_list .. ',', ',' .. uin .. ',' )
			if  pos_ then
				Log("in slist");
				return true   --忽略所有条件，一定成功
			end
		end


		--白名单
		if  condition_configs.uin_list then
			local uin = t_.uin
			local pos_  = string.find( ',' .. condition_configs.uin_list .. ',', ',' .. uin .. ',' )
			if  pos_ then
				--ok
			else
				Log("not in uin_list");
				return false
			end
		end


		--apiid
		if  condition_configs.apiids then
			--apiid 允许列表
			local finder_ = ',' .. t_.apiid .. ',';
			local ret     = string.find( ',' .. condition_configs.apiids .. ',', finder_ );
			if  ret then
				--可以显示
			else
				Log( "apiids check fail" )
				return false;   --不在列表中
			end
		elseif  condition_configs.apiids_no then
			--apiids 不开列表
			local finder_ = ',' .. t_.apiid .. ',';
			local ret     = string.find( ',' .. condition_configs.apiids_no .. ',', finder_ );
			if  ret then
				Log( "apiids_no check fail" )
				return false;   --在禁止列表中
			end
		end


		--ver
		if condition_configs.version_min and t_.ver then
			local version_min_ = uu.ver2i(condition_configs.version_min);
			local version_now_ = uu.ver2i(t_.ver);
			Log( "version=" .. version_min_ .. "/" .. version_now_ );
			if  version_min_ > version_now_ then
				Log( "version_min check fail" )
				return false;
			end
		end


		if condition_configs.version_max and t_.ver then
			local version_max_  = uu.ver2i(condition_configs.version_max);
			local version_now_  = uu.ver2i(t_.ver);
			Log( "version=" .. version_max_ .. "/" .. version_now_ );
			if  version_max_ < version_now_ then
				Log( "version_max check fail" )
				return false;
			end
		end


		--语言
		if  condition_configs.lang and t_.lang then
			local lang_ = t_.lang
			Log( "lang=" .. lang_ .. " | " ..  condition_configs.lang );
			if  tostring(lang_) == tostring(condition_configs.lang) then
				--匹配
			else
				Log("lang check fail" );
				return false;
			end
		end


		--语言组合
		if  condition_configs.langs and t_.lang then
			local finder_ = ',' .. t_.lang .. ',';
			local ret     = string.find( ',' .. condition_configs.langs .. ',', finder_ );
			Log( "langs=" .. finder_ .. " | " ..  condition_configs.langs );
			if  ret then
				--匹配
			else
				Log("langs check fail" );
				return false;
			end
		end


		--time
		if  condition_configs.start_time then
			local now_ = uu.now()
			local start_time_ = uu.get_time_stamp( condition_configs.start_time );
			if  now_ < start_time_ then
				Log( "start_time check fail" )
				return false
			end
		end

		if  condition_configs.end_time then
			local now_ = uu.now()
			local end_time_ = uu.get_time_stamp( condition_configs.end_time );
			if  now_ > end_time_ then
				Log( "end_time check fail" )
				return false
			end
		end

		if  condition_configs.countrys and t_.country then
			--apiid 允许列表
			local finder_ = ',' .. t_.country .. ',';
			local ret     = string.find( ',' .. condition_configs.countrys .. ',', finder_ );
			if  ret then
				--可以显示
			else
				return false;   --不在列表中
			end
		elseif  condition_configs.noCountrys and t_.country then
			--apiids 不开列表
			local finder_ = ',' .. t_.country .. ',';
			local ret     = string.find( ',' .. condition_configs.noCountrys .. ',', finder_ );
			if  ret then
				return false;   --在禁止列表中
			end
		end

		--可以显示
		return true;

	else
		--配置为空
		if  default_ then
			return default_
		else
			return false
		end
	end

end



-------------------------------------S8------------
----- 基于偏移量的复杂可变加密 --------------------
FOO.ns_http_sec_s8 = {

	select_index = 0,           ---指标值

	g_myb64chars_list = {},     ---后面进行初始化

	g_myb64chars_temp = {},

	init_list = function()
		--	--自定义的base64，与正式版本不一样(不能修改g_myb64chars)
		--	g_myb64chars = 'Vg21WQ5KdRt0yNpc' .. 'r9m4O3PoHaZvsLe' .. 'CY8FjSwiTkUbuEBIJ' .. 'lAG7fqXM6xDnzh-;',
		--	g_myb64chars_list = {},     ---后面进行初始化

		local list_head_ = FOO.ns_http_sec.g_myb64chars    --26+26+10+2 = 62+2
		for i=1, 50 do
			local string_ = string.sub( list_head_, i+3, 62 ) .. string.sub( list_head_, 1, i+3-1 ) .. '-;'
			log.day_list( "ns_http_sec_s8", i, string_ )
			FOO.ns_http_sec_s8.g_myb64chars_list [ #FOO.ns_http_sec_s8.g_myb64chars_list + 1 ] = string_
		end
		log.day_list( "ns_http_sec_s8", 'a', FOO.ns_http_sec.g_myb64chars )
	end,


	--url加密
	encodeS8Url = function( url_ )
		Log( "encodeS8Url=" .. url_ );
		local url_new_ = url_;

		local pos_ = string_find( url_, "?" );
		--http://xxxx.com/yyyy?aaaa=bbbb&ccc=dddd
		if  pos_ and pos_ > 10 then
			--local u1 = string_sub( url_, 1, pos_ );
			--Log( "u1====" .. u1 );

			local u2 = string_sub( url_, pos_+1 );
			--Log( "u2====" .. u2 );
			--加密u2
			url_new_ = FOO.ns_http_sec_s8.getS8( u2 );
		end

		return url_new_;
	end,


	--url解密
	decodeS8Url = function()
		log.day_list( "auth", "call decodeS8Url" );
		uu.var_dump( ngx.ctx.m_params );

		if  ngx.ctx.m_params.s8 then
			local head_   = string_sub( ngx.ctx.m_params.s8, 1, 5)
			local tail_   = string_sub( ngx.ctx.m_params.s8, 8) or ""

			local  md5_ = ngx.md5( "s8" .. tail_ );
			local  s8t_ = string_sub( md5_, 7, 11);
			if  head_ == s8t_ then
				log.day_list( "auth", "s8_match_ok" );
			else
				log.day_list( "auth", "s8_match_fail", ngx.var.request_uri );
				return false;
			end

			local select_ = string_sub( ngx.ctx.m_params.s8, 6, 7)
			local select_num_ = tonumber( select_, 16 )
			log.day_list( "auth", "s8_select", select_, select_num_ );
			local s8_ = FOO.ns_http_sec_s8.FromMyBase64_s8( tail_, select_num_ ) or "";
			ngx.ctx.request_uri_s8 = s8_;
			--Log( "s8=" .. s8_ );
			log.day_list( "auth", "decodeS8Url_over", s8_ );

			ngx.ctx.m_params = ngx.decode_args( s8_ );
		end

		return true;
	end,


	--url解密(网关专用)
	-- 与decodeS8Url的区别：  1. 会额外解析参数到 m_params_s8    2.会剥离s8e校验
	decodeS8Url_ma_gate = function()
		--Log( "call decodeS8Url_ma_gate" );
		--uu.var_dump( ngx.ctx.m_params );

		--Log( "call s8t=" .. (ngx.ctx.m_params.s8t or "nil") );
		--Log( "call s8 =" .. (ngx.ctx.m_params.s8  or "nil") );

		local head_   = string_sub( ngx.ctx.m_params.s8, 1, 5)
		local tail_   = string_sub( ngx.ctx.m_params.s8, 8) or ""

		local  md5_ = ngx.md5( "s8" .. tail_ );
		local  s8t_ = string_sub( md5_, 7, 11);
		if  head_ == s8t_ then
			log.day_list( "auth", "s8_match_ok" );
		else
			log.day_list( "auth", "s8_match_fail", ngx.var.request_uri );
			return false;
		end

		local select_ = string_sub( ngx.ctx.m_params.s8, 6, 7)
		local select_num_ = tonumber( select_, 16 )
		log.day_list( "auth", "s8_select", select_, select_num_ );
		local s8_ = FOO.ns_http_sec_s8.FromMyBase64_s8( tail_, select_num_ ) or "";
		ngx.ctx.request_uri_s8 = s8_;

		ngx.ctx.m_params_s8 = ngx.decode_args( s8_ );   --gate only
		return true;
	end,


	--获得url s8加密
	getS8 = function( s8key )
		FOO.ns_http_sec_s8.select_index = FOO.ns_http_sec_s8.select_index + 1
		if  FOO.ns_http_sec_s8.select_index > 200 then
			FOO.ns_http_sec_s8.select_index = 1   ---限制范围1到200+10
		end
		local  select_ = FOO.ns_http_sec_s8.select_index + 10
		local  u2sec = FOO.ns_http_sec_s8.ToMyBase64_s8( s8key, select_ );
		local  md5 = ngx.md5( "s8" .. (u2sec or "") );
		local  s8t = string_sub( md5, 7, 11);
		return s8t .. string.format("%x", select_) .. u2sec
	end,


	--不能直接调用
	ToMyBase64_s8 = function(source_str, p_select_ )
		local select_ = tonumber( p_select_ ) % 50
		local b64chars = FOO.ns_http_sec_s8.g_myb64chars_list[select_];
		--local s64 = ''
		local s64_list = {}
		local str = source_str

		while #str > 0 do
			local bytes_num = 0
			local buf = 0

			for byte_cnt=1,3 do
				buf = (buf * 256)
				if #str > 0 then
					buf = buf + string_byte(str, 1, 1)
					str = string_sub(str, 2)
					bytes_num = bytes_num + 1
				end
			end

			local b64char = '';
			for group_cnt=1,(bytes_num+1) do
				b64char = math_fmod(math_floor(buf/262144), 64) + 1
				--s64 = s64 .. string_sub(b64chars, b64char, b64char)
				s64_list[ #s64_list + 1 ] = string_sub(b64chars, b64char, b64char)
				buf = buf * 64
			end

			for fill_cnt=1,(3-bytes_num) do
				--s64 = s64 .. '_'
				s64_list[ #s64_list + 1 ] = '_'
			end
		end

		--return s64
		return table_concat( s64_list )
	end,


	--不能直接调用
	FromMyBase64_s8 = function(str64, p_select_)
		local select_ = tonumber( p_select_ ) % 50

		local temp
		if  FOO.ns_http_sec_s8.g_myb64chars_temp[select_] then
			temp = FOO.ns_http_sec_s8.g_myb64chars_temp[select_]
		else
			local b64chars = FOO.ns_http_sec_s8.g_myb64chars_list[select_];
			temp = {};
			for i=1,64 do
				temp[string_sub(b64chars,i,i)] = i
			end
			temp['_']=0
			FOO.ns_http_sec_s8.g_myb64chars_temp[select_] = temp;
		end


		--local str=""
		local str_list = {}
		for i=1,#str64,4 do
			if i>#str64 then
				break
			end
			local data = 0
			local str_count=0
			for j=0,3 do
				local str1=string_sub(str64,i+j,i+j)
				if not temp[str1] then
					return
				end
				if temp[str1] < 1 then
					data = data * 64
				else
					data = data * 64 + temp[str1]-1
					str_count = str_count + 1
				end
			end
			for j=16,0,-8 do
				if str_count > 0 then
					--str=str..string_char(math_floor(data/math_pow(2,j)))
					----data=math.mod(data,math.pow(2,j))
					--data=data % math_pow(2,j)
					--str_count = str_count - 1

					local m_ = math_pow(2,j)
					str_list[ #str_list + 1 ] = string_char(math_floor(data/m_))
					data=data % m_
					str_count = str_count - 1
				end
			end
		end

		--return str
		return table_concat( str_list )
	end,

}




-------------------------------------S7----mybase64加解密--------
FOO.ns_http_sec = {   ---host
	--自定义的base64，与正式版本不一样(不能修改g_myb64chars)
	g_myb64chars = 'Vg21WQ5KdRt0yNpc' .. 'r9m4O3PoHaZvsLe' .. 'CY8FjSwiTkUbuEBIJ' .. 'lAG7fqXM6xDnzh-;';

	--url加密
	encodeS7Url = function( url_ )
		--Log( "encodeS7Url=" .. url_ );
		local url_new_ = url_;

		local pos_ = string_find( url_, "?" );
		--http://xxxx.com/yyyy?aaaa=bbbb&ccc=dddd
		if  pos_ and pos_ > 10 then
			local u1 = string_sub( url_, 1, pos_ );
			local u2 = string_sub( url_, pos_+1 );			
			--Log( "u1====" .. u1 );
			--Log( "u2====" .. u2 );

			--加密u2
			local u2sec, s7t  = FOO.ns_http_sec.getS7( u2 );
			url_new_  = u1 .. "s7t=" .. s7t .. "&s7=" .. u2sec;
		end
		return url_new_;
	end,


	--url解密
	decodeS7Url = function()
		--Log( "call decodeS7Url" );
		uu.var_dump( ngx.ctx.m_params );

		--Log( "call s7t=" .. (ngx.ctx.m_params.s7t or "nil") );
		--Log( "call s7 =" .. (ngx.ctx.m_params.s7  or "nil") );
		if  ngx.ctx.m_params.s7t and ngx.ctx.m_params.s7 then
			local  md5_ = ngx.md5( "s7" .. (ngx.ctx.m_params.s7 or "") );
			local  s7t_ = string_sub( md5_, 7, 11);
			if  ngx.ctx.m_params.s7t == s7t_ then
				--log.day( "auth", "s7_match_ok" );
			else
				log.day( "auth", "s7_match_fail|" .. ngx.var.request_uri );
				return false;
			end

			local s7_ = FOO.ns_http_sec.FromMyBase64( ngx.ctx.m_params.s7 ) or "";
			ngx.ctx.request_uri_s7 = s7_;
			--Log( "s7=" .. s7_ );

			ngx.ctx.m_params = ngx.decode_args( s7_ );
		end
		return true;
	end,


	--url解密(网关专用)
	-- 与decodeS7Url的区别：  1. 会额外解析参数到 m_params_s7    2.会剥离s7e校验
	decodeS7Url_ma_gate = function()
		--Log( "call decodeS7Url_ma_gate" );
		--uu.var_dump( ngx.ctx.m_params );

		--Log( "call s7t=" .. (ngx.ctx.m_params.s7t or "nil") );
		--Log( "call s7 =" .. (ngx.ctx.m_params.s7  or "nil") );

		local  md5_ = ngx.md5( "s7" .. (ngx.ctx.m_params.s7 or "") );
		local  s7t_ = string_sub( md5_, 7, 11);
		if  ngx.ctx.m_params.s7t == s7t_ then
			--log.day( "auth", "s7_match_ok" );
		else
			log.day( "auth", "s7_match_fail|" .. ngx.var.request_uri );
			return false;
		end

		local s7_ = FOO.ns_http_sec.FromMyBase64( ngx.ctx.m_params.s7 ) or "";

		--剥离 &s7e
		local pos_ = string_find( s7_, "s7e=" );
		if  pos_ and pos_ > 5 then
			s7_ = string_sub( s7_, 1, pos_- 2 );
		end

		ngx.ctx.request_uri_s7 = s7_;
		--Log( "s7=" .. s7_ );

		ngx.ctx.m_params_s7 = ngx.decode_args( s7_ );   --gate only
		return true;
	end,


	--获得url s7加密
	getS7 = function( s7key )
		local  u2sec = FOO.ns_http_sec.ToMyBase64( s7key );
		local  md5 = ngx.md5( "s7" .. (u2sec or "") );
		local  s7t = string_sub( md5, 7, 11);
		return u2sec, s7t;
	end,

	--不能直接调用
	ToMyBase64 = function(source_str)
		local b64chars = FOO.ns_http_sec.g_myb64chars;
		--local s64 = ''
		local s64_list = {}
		local str = source_str

		while #str > 0 do
			local bytes_num = 0
			local buf = 0

			for byte_cnt=1,3 do
				buf = (buf * 256)
				if #str > 0 then
					buf = buf + string_byte(str, 1, 1)
					str = string_sub(str, 2)
					bytes_num = bytes_num + 1
				end
			end

			local b64char = '';
			for group_cnt=1,(bytes_num+1) do
				b64char = math_fmod(math_floor(buf/262144), 64) + 1
				--s64 = s64 .. string_sub(b64chars, b64char, b64char)
				s64_list[ #s64_list + 1 ] = string_sub(b64chars, b64char, b64char)
				buf = buf * 64
			end

			for fill_cnt=1,(3-bytes_num) do
				--s64 = s64 .. '_'
				s64_list[ #s64_list + 1 ] = '_'
			end
		end

		--return s64
		return table_concat( s64_list )
	end,

	--不能直接调用
	FromMyBase64 = function(str64)
		--local b64chars = FOO.ns_http_sec.g_myb64chars;
		--local temp={}
		--for i=1,64 do
			--temp[string_sub(b64chars,i,i)] = i
		--end
		--temp['_']=0

		local temp
		if  FOO.ns_http_sec.g_myb64chars_temp then
			temp = FOO.ns_http_sec.g_myb64chars_temp;
		else
			local b64chars = FOO.ns_http_sec.g_myb64chars;
			temp = {};
			for i=1,64 do
				temp[string_sub(b64chars,i,i)] = i
			end
			temp['_']=0
			FOO.ns_http_sec.g_myb64chars_temp = temp;
		end


		--local str=""  ---string1
		local str_list = {}
		for i=1,#str64,4 do
			if i>#str64 then
				break
			end
			local data = 0
			local str_count=0
			for j=0,3 do
				local str1=string_sub(str64,i+j,i+j)
				if not temp[str1] then
					return
				end
				if temp[str1] < 1 then
					data = data * 64
				else
					data = data * 64 + temp[str1]-1
					str_count = str_count + 1
				end
			end
			for j=16,0,-8 do
				if str_count > 0 then
					--str=str..string_char(math_floor(data/math_pow(2,j)))
					----data=math.mod(data,math.pow(2,j))
					--data=data % math_pow(2,j)
					--str_count = str_count - 1

					local m_ = math_pow(2,j)
					str_list[ #str_list + 1 ] = string_char(math_floor(data/m_))
					data=data % m_
					str_count = str_count - 1
				end
			end
		end

		--return str   ---string1
		return table_concat( str_list )
	end,

}



--检查auth for openId
FOO.checkOpenIdAuth = function( authA, open_id, uin_ )   --host
	if  authA and open_id and uin_ then
		local md5 = ngx.md5 ( open_id .. '#ou#' .. uin_ );
		if  md5 == string.lower( authA ) then
			return true;
		end
	end
	return false;
end;



--检查tk1 tk2 tk3 ... tks
FOO.check_tks_sum = function()    --host
	--get_tk_sum = function( content )
	--local  md5 = gFunc_getmd5 ( "_tk_" .. (content or "") )
	--local  ret = string.sub( md5, 7, 11)
	--return ret
	--end,

	--有上报数据
	if  ngx.ctx.m_params.tks then
		local tks_content_ = ""
		for i=1, 5 do
			if  ngx.ctx.m_params['tk' .. i ] then
				tks_content_ = tks_content_ .. "_" .. ngx.ctx.m_params['tk' .. i ]
			end

			if  #tks_content_ > 0 then
				local  md5 = ngx.md5 ( "_tk_" .. tks_content_ )
				local  ret = string.sub( md5, 7, 11)
				if  ret == ngx.ctx.m_params.tks then
					log.debug( "tks check ok" )
					return true
				else
					log.debug( "tks check sum fail" )
				end
			end
		end

		log.error( "tks check fail" )
		return false
	else
		return true
	end
end



---------------------------------------------------------------------------------


-- 检查uin合法性 不退出
FOO.check_uin_safe = function( uin_ )
	local uin = tonumber( uin_ ) or 0;
	if  uin < 1000 then
		log.error( "uin error=" .. (uin_ or 'nil') );
		return false
	end
	ngx.ctx.m_params.uin = uin;
	return true
end


--按照uin和参数time获得s2 salt ( root )
FOO.genS2Salt = function()
	local time_ = ngx.ctx.m_params.s2t

	-- &s2t=&s2t=1514188488
	if  type(time_) == 'table' then
		for k, v in pairs(ngx.ctx.m_params.s2t) do
			if  v and #v >= 3 then
				time_ = v
			end
		end
		ngx.ctx.m_params.s2t = time_   --转换s2t
	end

	if  time_ and #time_==10 then     --1494388067
		local uin_  = ngx.ctx.m_params.uin
		local ret = ngx.md5( uin_ .. FOO.auth_key .. time_ )
		--ret = string_sub( ret, 1, 8 )
		--log.debug( "new s2=" .. ret .. ", t=" .. time_  )

		return ret;
	else
		--log.debug( "old s1" );
		return '#_php_miniw_2016_#';
	end
end



--按照uin和参数time获得s2 salt
FOO.genS2SaltByUinTime = function(uin, time_)
	if  time_ and #time_==10 then     --1494388067
		local uin_  = uin;
		local ret = ngx.md5( uin_ .. FOO.auth_key .. time_ );
		return ret;
	end
	return "format_error";
end



-- 检查act auth合法性，出错不退出
FOO.check_act_auth_no_exit = function()
	local time_ = tonumber(ngx.ctx.m_params.time or 0) or 0;
	if  time_ <= 0 then
		return 1
	end

	local uin_ = tonumber( ngx.ctx.m_params.uin or 0 ) or 0;
	if  uin_ and uin_ >= 1000 then
		--normal
		ngx.ctx.m_params.uin = uin_
	else
		return 2
	end

	--auth
	if  ngx.ctx.m_params.auth then
		local auth_ = ngx.md5 ( time_ .. FOO.genS2Salt() .. uin_ );
		if  auth_ == ngx.ctx.m_params.auth then
			return 0  			--normal
		end
	end

	return 3
end



-- 检查cmd token合法性，出错不退出
FOO.check_cmd_auth_no_exit = function()
	--time
	local time_ = tonumber(ngx.ctx.m_params.time or 0);
	if  time_ <= 0 then
		return 1
	end

	--uin
	local uin_ = tonumber( ngx.ctx.m_params.uin or 0 );
	if  uin_ and uin_ >= 1000 then
		--normal
		ngx.ctx.m_params.uin = uin_
	else
		return 2
	end

	local token_ = ngx.ctx.m_params.token;
	local cmd_   = ngx.ctx.m_params.cmd;

	--cmd auth
	return FOO.check_comm_inner_token_no_exit( token_, uin_, time_, cmd_ );
end


-- 检查auth comm inner的正确性，出错不强制退出
FOO.check_comm_inner_token_no_exit = function( token_, uin_, time_, cmd_, ext_info_ )
	local  ret_ =  FOO.gen_comm_inner_token( uin_, time_, cmd_, ext_info_ );
	return FOO.private_check_token_eq_safe(token_, ret_);
end


--普通内部验证 (删除文件)
FOO.gen_comm_inner_token = function( uin_, time_, cmd_, ext_info_ )
	--local  token_ =  ngx.md5 ( (uin_ or "") .. '#LY1006#' .. (time_ or "")
			--.. '#' .. (cmd_ or "") .. '#' .. (ext_info_ or "") );

	local token_ = ngx.md5 ( table_concat( {(uin_ or ""), '#LY1006#', (time_ or ""),
                                 '#', (cmd_ or ""), '#', (ext_info_ or "")} ) );
	return token_;
end

FOO.gen_map_comment_inner_token = function( uin_, time_)
	local token_ = ngx.md5 ( table_concat( {(uin_ or ""), (time_ or ""), '_com_2021-10-01_'}))
	return token_
end

-- 检测两个token值是否一致， 0=ok  1=fail
FOO.private_check_token_eq_safe = function( t1, t2 )
	if  t1 == t2 then
		return 0
	elseif  ns_env.auth_debug==1 and ngx.ctx.m_params.test=='1' then
		log.day( "error", "error_token1" );
		log.debug( "error_token1, debug." );
		return 0
	else
		log.day( "error", "error_token2" );
		return 1
	end
end



---检查php发过来的ctoken
function FOO.check_ctoken( ctoken_ )
	if  ctoken_ then
		---1610440852_fuli_9485c5efd3e3230f219cf47aedc764ab_33349
		local t_ = uu.split( ctoken_, '_' )
		if  #t_ >=4 then
			--$time_ . '_' . $user_short_ . '_' . md5( $time_ . $user_ . '_private_salt2_miniw_' )
			--. '_' . rand(10000, 99999);
			local time_ = t_[1]
			local user_short_ = t_[2]
			local user_ = "gm" .. user_short_
			local token_cal_ = ngx.md5( time_ .. user_ .. '_private_salt2_miniw_' )
			if  token_cal_ == t_[3] then
				return true, user_short_
			end
		end
	end
	return false
end

--------------------------------------------------------------
-- 说明：登陆SDK获取token校验数据
-- 参数：Token				token
-- 		CPID				接入方id
-- 		ProductKey			产品key
-- 		Auth				安全校验码l
-- 返回：n					状态码
--		s 					描述
FOO.get_token_data = function( t_param_list, n_apiid )
	local s_secret 		= ''
	local t_key_params 	= {}

	t_param_list 				= t_param_list or {}
	t_param_list["CPID"] 		= FOO.s_cpid
	t_param_list["ProductKey"] 	= FOO.t_product_key[n_apiid] or ''

	for i in pairs(t_param_list) do
		table.insert(t_key_params,i)
	end

	table.sort(t_key_params)
	for _,v in pairs(t_key_params) do
		if v then s_secret = s_secret .. v .. '=' .. t_param_list[v] end
	end

	local t_count   = #FOO.login_SDK_server_url
	local n_index   = math_random(t_count)
	local s_url 	= FOO.login_SDK_server_url[n_index]
	local t_header  = {["Content-Type"] = "application/json"}

	local t_sha_ob  = hmac:new(FOO.s_hmac_SHA256, hmac.ALGOS.SHA256)
	local s_auth 	= t_sha_ob:final(s_secret, true)
	local t_body   	= t_param_list
	t_body["Auth"]  = s_auth

	local n_ret, t_body = ns_network.postHttpsPage(s_url, uu.table2json(t_body), nil, nil, t_header);
	if  n_ret == 200 then
		local t_result = uu.json2table(t_body)
		if t_result and t_result.Code and tonumber(t_result.Code) ~= 0 then
			log.error( "token error:" .. 'code=' .. t_result.Code .. '|' .. s_url .. uu.table2json(t_body) .. '|' .. uu.table2json(t_param_list));
		end
		return 0, t_result
	else
		log.error( "token error:" .. 'n_ret=' .. n_ret .. '|' .. s_url .. uu.table2json(t_body) .. '|' .. uu.table2json(t_param_list));
		return n_ret, t_body
	end
end

---生成一个data_cache服务器使用key
function FOO.gen_data_cache_auth( name_, pp_  )
	local str_ = table_concat( {  name_, "_dc3_miniw_", pp_.time, pp_.func,
								 (pp_.key or ""),
								 (pp_.hash or ""),
								 (pp_.value or "") }, '-' )
	return ngx.md5( str_ )
end


function FOO.gen_all_param_auth(uin, st, ct, key)
	if not (uin and st and ct and key) then
		return
	end

	local token = ngx.md5(uin .. key .. st)
	return ngx.md5(ct .. token .. uin)
end


return FOO;
